/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jfonia.model.relations;

import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.basics.ValueNode;
import org.jfonia.connect5.intervals.Interval;
import org.jfonia.connect5.intervals.ListObserver;
import org.jfonia.connect5.relations.Relation;
import org.jfonia.constants.ModelConstants;
import org.jfonia.constants.SymbolConstants;
import org.jfonia.model.Sequence;
import org.jfonia.model.TempoMap;
import org.jfonia.model.TempoNode;
import org.jfonia.model.elements.TimeSignature;

/**
 *
 * @author Jannes Plyson
 */
public class TicksToTimeRelation implements Relation,ListObserver{
    private ValueNode<Integer> ticks;
    private TempoMap tempoMap;    
    private Sequence<TimeSignature> timeSignatureSequence;
    private ValueNode<Boolean> lockPerformance;
    private ValueNode<Long> timeOffset;
    private MutableValueNode<Long> nanoSeconds;

    //TODO: template parameter T (NotationSequence<T>)
    public TicksToTimeRelation(ValueNode<Integer> ticks, TempoMap tempoMap, Sequence<TimeSignature> timeSignatureSequence,ValueNode<Boolean> lockPerformance,ValueNode<Long> timeOffset, MutableValueNode<Long> nanoSeconds) {
        this.ticks = ticks;
        this.tempoMap = tempoMap;
        this.timeSignatureSequence = timeSignatureSequence;
        this.lockPerformance = lockPerformance;
        this.timeOffset = timeOffset;
        this.nanoSeconds = nanoSeconds;        
        switchOn();
    }

    public void onNotify(Object source) {
        if(source == ticks || source == lockPerformance || source == tempoMap){
                updateNanoSeconds();            
        }
    }


    public void updateNanoSeconds(){
        if(!lockPerformance.getValue()){
            int bpm = ((TempoNode)tempoMap.getIntervalFromValue(ticks.getValue())).getBPM();            
            int beatsize = ((TimeSignature)(timeSignatureSequence.getIntervalFromValue(ticks.getValue()))).getDenominator();            
            int beatsizeTicks = SymbolConstants.DIVISOR/beatsize;                        
            long value = (60l*ModelConstants.PERFORMANCE_TO_SECOND*ticks.getValue())/(bpm*beatsizeTicks);
            value += timeOffset.getValue();            
            nanoSeconds.setValue(value);
        }
    }

    public void switchOn()
    {
            ticks.addObserver(this);
            tempoMap.addObserver(this);
            timeSignatureSequence.addObserver(this);
            lockPerformance.addObserver(this);
            timeOffset.addObserver(this);
            updateNanoSeconds();
    }

    public void switchOff()
    {
            ticks.removeObserver(this);
            tempoMap.removeObserver(this);
            timeSignatureSequence.removeObserver(this);
            lockPerformance.removeObserver(this);
            timeOffset.removeObserver(this);
    }

    public void intervalAdded(Interval interval) {        
        updateNanoSeconds();
        
    }    

    public void intervalEndChanged(Interval interval) {                
        updateNanoSeconds();
    }

    public void intervalRemoved(Interval interval, int index) {        
        updateNanoSeconds();
    }

}
